<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class SignatureMiddleware
{
    /**
     * 组织签名参数
     * @param array $params
     * @return string
     */
    private function organizeParams(array $params): string
    {
        // 过滤并排序参数
        $filteredKeys = array_filter(array_keys($params), function ($key) {
            return trim($key) !== 'sign';
        });
        sort($filteredKeys);

        if (empty($filteredKeys)) {
            return '';
        }

        // 拼接参数
        $pairs = array_map(function ($key) use ($params) {
            $value = $params[$key];

            // 如果值是对象或数组，编码成JSON字符串
            if (is_array($value) || is_object($value)) {
                $value = json_encode($value, JSON_UNESCAPED_SLASHES);
            }
            if (is_bool($value)) {
                $value = $value ? 'true' : 'false';
            }

            return $key . '=' . $value;
        }, $filteredKeys);

        // 获取签名密钥，如果环境变量中没有配置则使用默认值
        $signKey = env('SIGN_KEY', '');

        return $signKey . implode('&', $pairs) . $signKey;
    }

    /**
     * 验证签名
     * @param array $params 请求参数
     * @param string $sign 签名
     * @return bool
     */
    private function verifySign(array $params, string $sign): bool
    {
        if (empty($params)) {
            return false;
        }

        // 组织参数字符串
        $signStr = $this->organizeParams($params);
        if (empty($signStr)) {
            return false;
        }

        // MD5加密验证
        $serverSign = md5($signStr);

        return $sign === $serverSign;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        try {
            // 获取所有参数
            $params = $request->all();

            // 获取签名
            $sign = $params['sign'] ?? '';
            if (empty($sign)) {
                return response()->json([
                    'code' => 402,
                    'message' => 'Missing signature parameter'
                ]);
            }

            // 验证签名
            if (!$this->verifySign($params, $sign)) {
                return response()->json([
                    'code' => 402,
                    'message' => 'Signature verification failed'
                ]);
            }

            return $next($request);
        } catch (\Exception $e) {
            return response()->json([
                'code' => 402,
                'message' => 'Signature verification error: ' . $e->getMessage()
            ]);
        }
    }
}
